﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data.Entity.Validation;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.SessionState;
using com.nm.library.com.nm.Helper;
using george.Web.Helper;
using com.nm.ApiServer.Attributes;
using com.nm.Cache;
using com.nm.interfaces;
using Newtonsoft.Json;
using com.nm.library.Factorys;
using com.nm.Attributes;
using com.nm.db.Models.Systems;
using com.nm.Helper;
using com.nm.library;
using com.nm.library.Helper;
using Newtonsoft.Json.Linq;
using george.Helper;
using george.Web;
using Renci.SshNet;
using System.IO;

// ReSharper disable once CheckNamespace
namespace com.nm.ApiServer {
	/// <summary>
	/// 所有API的基类，用来分发Action
	/// </summary>
	public class BaseHandler : ISessionContext, IHttpHandler, IReadOnlySessionState {
		/// <summary>
		/// Session
		/// </summary>
		public HttpSessionState Session { get; protected set; }
		/// <summary>
		/// 当前请求信息
		/// </summary>
		public HttpRequest Request { get; protected set; }
		/// <summary>
		/// 页面返回信息
		/// </summary>
		public HttpResponse Response { get; protected set; }
		/// <summary>
		/// 服务器相关
		/// </summary>
		public HttpServerUtility Server { get; protected set; }
		/// <summary>
		/// HttpContext
		/// </summary>
		public HttpContext Context { get; protected set; }

		bool IHttpHandler.IsReusable => false;

		/// <summary>
		/// 控制器名称
		/// </summary>
		public string Controller => this.GetType().Name.Replace("Handler", "");

		/// <summary>
		/// 保存当前APP信息
		/// </summary>
		protected ApiConfig ApiApp { get; set; }
		/// <summary>
		/// 系统 Token（AccessToken）
		/// </summary>
		protected string Token { get; set; }

		/// <summary>
		/// 执行API（由 Core.Init调用）
		/// </summary>
		/// <param name="context"></param>
		/// <param name="action"></param>
		/// <param name="parameters"></param>
		/// <returns></returns>
		public object Execute(HttpContext context, string action, string parameters) {
			Context = context;
			Session = context.Session;
			Request = context.Request;
			Response = context.Response;
			Server = context.Server;

			var beginTime = DateTime.Now;
			var thisType = this.GetType();
			object r = null;
			if (!CheckAccessToken(thisType, out r, false)) return r;
			CheckUserToken(Request, this.ApiApp);

			if (CheckAttribute(thisType, out r, beginTime)) {
				try {
					r = parseMethod(action, parameters);
					log(beginTime, false);
				} catch (ArgumentException ae) {
					r = Error(ae.Message, 500);
					log(beginTime, true);
				} catch (TargetInvocationException e) {
					r = Error(e, 501);
					log(beginTime, true);
					//} catch (JsonSerializationException e) {
					//    r = Error(e, 501);
					//    log(beginTime, true);
				} catch (Exception e) {
					r = Error(e, 500);
					log(beginTime, true);
				}
			}
			//AddApiCallLog(parameters, beginTime, r);
		    AddSysLog();
            return r;
		}

		void IHttpHandler.ProcessRequest(HttpContext context) {
			Context = context;
			Session = context.Session;
			Request = context.Request;
			Response = context.Response;
			Server = context.Server;

			var beginTime = DateTime.Now;
			var content = Request.GetPostContent();
			var thisType = this.GetType();
			object r = null;
			this.Action = string.IsNullOrWhiteSpace(Request.PathInfo)
				? Request.Get("a", string.Empty)
				: Request.PathInfo.Split('/').Distinct().FirstOrDefault(item => string.IsNullOrWhiteSpace(item) == false);

			if (!CheckAccessToken(thisType, out r)) return;
			CheckUserToken(Request, this.ApiApp);
			if (CheckAttribute(thisType, out r, beginTime)) {
				try {
					r = parseMethod(Request.PathInfo, content);
					log(beginTime, false);
				} catch (ArgumentException ae) {
					r = Error(ae.Message);
					log(beginTime, true);
					//} catch (JsonSerializationException e) {
					//    r = Error(e, 501);
					//    log(beginTime, true);
				} catch (TargetInvocationException e) {
					r = Error(e.InnerException ?? e, 501);
					log(beginTime, true);
				} catch (Exception e) {
					r = Error(e, 500);
					log(beginTime, true);
				}
			}
			output(r);
			//AddApiCallLog(content, beginTime, r);
            AddSysLog();
        }
		/// <summary>
		/// 检查控制器的权限控制标志，成功返回 true
		/// </summary>
		/// <param name="thisType"></param>
		/// <param name="r"></param>
		/// <param name="beginTime"></param>
		/// <returns></returns>
		protected bool CheckAttribute(Type thisType, out object r, DateTime beginTime) {
			r = null;
			if (string.Compare("GetDTD", this.Action, StringComparison.OrdinalIgnoreCase) == 0)
				return true;

			var attribs = thisType.GetCustomAttributes(true);
			var isMustLogin = attribs.Any(item => item is MustLoginAttribute);
			var isMustAdmin = attribs.Any(item => item is MustAdminAttribute);
			var isMustBackend = attribs.Any(item => item is MustBackendAttribute);
		    var isMustRole = attribs.Any(item=>item is RoleBcAttribute);

			if (isMustAdmin && (string.IsNullOrWhiteSpace(this.UserId.ToString()) || MustAdminAttribute.Check(this.UserId.ToString()) == false)) {
				r = Error("必须是管理员", 403);
				log(beginTime, true);
				return false;
			}
			if (isMustBackend && string.IsNullOrWhiteSpace(this.UserId.ToString())) {
				r = Error("必须是后台用户", 403);
				log(beginTime, true);
				return false;
			}
		    if (isMustLogin &&
		        (string.IsNullOrWhiteSpace(this.UserId.ToString()) || this.UserId == 0))
		    {
		        r = Error("执行该操作必须登录", 4009);
		        log(beginTime, true);
                return false;
		    }
		    if (isMustBackend) {
				return RcHelper.HasRights(this.UserId.ToString(), this.Controller, this.Action);
			}
		    if (isMustRole && RoleBcAttribute.CheckRole(this.UserId))
		    {
                r = Error("无执行此操作权限", 401);
                log(beginTime, true);
                return false;
            }
			//var attr1 = (MustRights)attribs.FirstOrDefault(item => item is MustRights);
			//if (attr1 != null && attr1.Check(UserInfo.StaffNo) == false) {
			//    r = Error("没有权限", 4003);
			//    log(beginTime, true);
			//}
			return true;
		}

		private static RedisClient _rcClient;
		static string getRedis(string key) {
			if (_rcClient == null)
				_rcClient = new RedisClient(ConfigurationHelper.Get<int>("redis-cache-index", 8));
			var pre = "km:cache:";
			return (string)_rcClient.GetStringValue(pre + key);
		}
		static bool existsRedis(string key) {
			if (_rcClient == null)
				_rcClient = new RedisClient(ConfigurationHelper.Get<int>("redis-cache-index", 8));
			var pre = "km:cache:";
			return _rcClient.KeyExists(pre + key);
		}

		/// <summary>
		/// 检查用户信息
		/// </summary>
		private static void CheckUserToken(HttpRequest Request, ApiConfig api) {
			var userToken = Request.Get("u", "");
			if (string.IsNullOrWhiteSpace(userToken)) return;
			if (!RedisCache.Exists(userToken) && !existsRedis(userToken)) {
				Log.Error($"用户Token已经过期 {userToken}，{Request.QueryString.ToString()}", "UserToken");
				return;
			}
		    if (UserInfo.UserID == "0" || string.IsNullOrWhiteSpace(UserInfo.UserCompanyId) ||
		        string.IsNullOrWhiteSpace(UserInfo.UserExtrSource))
		    {
		        Log.Error($"Session已经过期，{Request.QueryString.ToString()}", "Session");
		        return;
		    }

		    if (userToken.StartsWith("A:")) {
				//string UserId = RedisCache.Get(userToken);
				AdminUserFactory.Instance.CheckUserAccessToken(userToken);
				return;
			}
			if (userToken.StartsWith("N:")) {
				//string UserId = RedisCache.Get(userToken);
				string userName = RedisCache.GetString(userToken);
				if (string.IsNullOrWhiteSpace(userName))
					return;
				UserInfo.UserName = userName;
				UserInfo.AnonymousId = userToken;
				return;
			}
			try {
				var id = existsRedis(userToken)
					? getRedis(userToken)
					: RedisCache.GetString(userToken);
				var userId = 0;
				int.TryParse(id, out userId);
				//if (!myCache.Exists(userToken)) return;
				var userFactory = FactoryMaker.Get<IUserFactory>("user-facotry", "com.nm.db.MemberShipFactory,com.nm.db");
				var user = userId > 0
					? userFactory.GetUserByUserID(userId)
					: userFactory.GetUserByOpenId(id, 3);
				if (user == null) return;
				RedisCache.Expire(userToken, 30);
				userFactory.DoLogin(user);
                //用户手机系统类型统计
				//var dc = new OCity_KFContext();
				//if (dc.YhChatPhoneOsTypes.Any(i => i.CusId == user.CusId && i.OSType == api.OsType)) return;
				//dc.YhChatPhoneOsTypes.Add(new yh_chatPhoneOsType() {
				//	CusId = user.CusId,
				//	OSType = api.OsType,
				//	CreateDate = DateTime.Now
				//});
				//try {
				//	dc.SaveChanges();
				//} catch (Exception ex) {
				//	Log.Error(ex);
				//}
			} catch (Exception ex) {
				Log.Error(ex);
			}
		}

		/// <summary>
		/// 检查Token
		/// </summary>
		/// <param name="thisType"></param>
		/// <param name="r"></param>
		/// <param name="isOutput">是否输出错误信息</param>
		/// <returns> Token 无效 返回false</returns>
		protected bool CheckAccessToken(Type thisType, out object r, bool isOutput = true) {
			r = null;
			if (thisType == typeof(TokenHandler) || this.Controller == "Debuger") return true;
			if (string.Compare("GetDTD", this.Action, StringComparison.OrdinalIgnoreCase) == 0)
				return true;
			var token = Request.Get("token", "");
			if (string.IsNullOrWhiteSpace(token) && Session != null) {
				if (Session["token"] != null)
					token = Session["token"].ToString();
			}
            Token = token;
            return true;
            //////ApiApp = myCache.Get(token, "").FromJson<yhAPIApp>();
            try {
				ApiApp = RedisCache.GetAndDecodeJson<ApiConfig>(token);
			} catch (Exception ex) {
				// ignored
				Log.Error(ex);
			}
			if (ApiApp != null) {
				Token = token;

				return true;
			}
			r = this.Error("AccessToken " + token + "无效", 4001);
			if (isOutput)
				output(r);
			return false;
		}
		/// <summary>
		/// 把API的调用记录写到 Redis中
		/// </summary>
		/// <param name="parameters"></param>
		/// <param name="beginTime"></param>
		/// <param name="r"></param>
		protected void AddApiCallLog(string parameters, DateTime beginTime, object r) {
			var apiLog = new ApiLog() {
				Controller = this.Controller,
				Action = this.Action,
				CusID = this.UserId,
				IpAddress = Request.GetClientIpAddress(),
				BeginTime = beginTime,
				EndTime = DateTime.Now,
				Params = parameters,
			};
			if (ApiApp != null) {
				apiLog.AppName = ApiApp.AppName;
				apiLog.AppID = ApiApp.ID;
			}
			;
			var ar = (ApiResult)r;
			if (r != null) {
				apiLog.IsSuccess = ar.Success;
				apiLog.ErrorCode = ar.Code;
				apiLog.Message = ar.Message;
			}
			if (!Request.IsLocal) {
				Task.Run(() => ApiLog.SaveAsync(apiLog));
			}
		}

	    /// <summary>
	    /// 保存系统日志
	    /// </summary>
	    protected void AddSysLog()
	    {
	        var type = this.GetType();
	        var methods = type.GetMethod(this.Action);
	        var d = methods.GetCustomAttributes().FirstOrDefault(o => o is DescriptionAttribute);
            var content = "";
	        var descriptionAttribute = d as DescriptionAttribute;
	        if (descriptionAttribute != null) content = descriptionAttribute.Description;
	        // content = d.ConstructorArguments[0].Value.ToString();
	        var sysLog = new sys_log
	        {
	            Action = this.Controller + ":" + this.Action,
	            Operator = this.UserId,
	            HostAddress = Request.GetClientIpAddress(),
	            CreateTime = DateTime.Now,
	            LogContent = content,
	            OperationType = 0
	        };
	        //if (!Request.IsLocal)
	        {
	            Task.Run(() => ApiLog.SavaSysLog(sysLog));
	        }
	    }

	    /// <summary>
		/// 当前用户是否后台用户
		/// </summary>
		public bool IsBackgroundUser => !string.IsNullOrWhiteSpace(this.UserId.ToString());

		/// <summary>
		/// 当前用户ID（如果有登陆）
		/// </summary>
		public int UserId
        {
		    //get
		    //{
      //          //从redis中取用户信息
      //          var id = this.Session.Get("CurrentUserId", 0);
      //          UserInfo.UserID = id.ToString();
      //          return id;
      //          //var id = 0;
      //          //int.TryParse(UserInfo.UserID, out id);
      //          //return id;
      //      }

            get
            {
                int id = 0;
                var _uuid = UserInfo.UserID;
                int.TryParse(_uuid, out id);
                return id;
            }
        }


		/// <summary>
		/// 返回JSON
		/// </summary>
		/// <param name="r"></param>
		void output(object r) {
			SetHeader(Response);
			Response.AddHeader("Content-Type", "application/json");
			Response.Write(r.ToJson());
		}
		internal static void SetHeader(HttpResponse Response) {
			Response.ClearHeaders();
			Response.AddHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,Content-Type,Accept,Access-Control-Request-Method,X_FILENAME");
			Response.AddHeader("Access-Control-Allow-Methods", "GET,PUT,POST,HEAD,DELETE,OPTIONS");
			Response.AddHeader("Access-Control-Max-Age", "360000");
			Response.AddHeader("Access-Control-Allow-Credentials", "true");
			Response.AddHeader("Access-Control-Allow-Origin", "*");
		}
		/// <summary>
		/// 日志
		/// </summary>
		/// <param name="beginTime"></param>
		/// <param name="isError"></param>
		private void log(DateTime beginTime, bool isError) {
			var endTime = DateTime.Now;
			var st = endTime - beginTime;
			var ip = Request.GetClientIpAddress();
			if (isError) {
				Log.Error("{6}\n{3}\n执行API（{4}--{5}）错误：\n{0}-{1}\n{2}", "API",
					beginTime, endTime, st, ip,
					this.Controller,
					this.Action,
					this.ApiApp != null ? this.ApiApp.AppName : "NNNN");
			}
			//因为已经在Redis中记录了每个API的执行情况，所以这里就只记录错误信息
			// else {
			//	Log.WriteLog("{3}\n执行API（{4}--{5}）成功：\n{0}-{1}\n{2}", "API",
			//		Log.LogType.INFO, beginTime, endTime, st, ip,
			//		this.Controller,
			//		this.Action);
			//}
		}
		/// <summary>
		/// 处理方法
		/// </summary>
		/// <param name="path"></param>
		/// <param name="parameters"></param>
		/// <returns></returns>
		protected object parseMethod(string path, string parameters) {
			object result = null;
			var action = string.IsNullOrWhiteSpace(path)
				? Request.Get("a", string.Empty)
				: path.Split('/').Distinct().FirstOrDefault(item => string.IsNullOrWhiteSpace(item) == false);
			if (string.IsNullOrWhiteSpace(action))
				return Error("没有Action参数", 404);

			var type = GetType();
			var paramType = 1;
			if (Request.Headers.AllKeys.Contains("Caller")) {
				if (Request.Headers["Caller"] == "kmApiSDK") {
					paramType = 2;
				}
			}
			var ms = type.GetMethods();
			var m = ms.FirstOrDefault(item => string.CompareOrdinal(item.Name, action) == 0);
			if (m == null) return Error("没有此Action：" + action, 404);
			this.Action = m.Name;
			var attribs = m.GetCustomAttributes(false);
			var isAutoCovrtFromJSon = attribs.Any(item => item is JsonTypeAttribute);
			var isPassJson = attribs.Any(item => item is JSONDataAttribute);
			var isMustLogin = attribs.Any(item => item is MustLoginAttribute);
			var isMustAdmin = attribs.Any(item => item is MustAdminAttribute);
			var isMustBackend = attribs.Any(item => item is MustBackendAttribute);
            var isMustRole = attribs.Any(item => item is RoleBcAttribute);

            if (isMustAdmin && (string.IsNullOrWhiteSpace(this.UserId.ToString()) || MustAdminAttribute.Check(this.UserId.ToString()) == false)) {
				return Error("必须是管理员", 403);
			}
			if (isMustBackend && string.IsNullOrWhiteSpace(this.UserId.ToString())) {
				return Error("必须是后台用户", 403);
			}
			if (isMustBackend){
				if (RcHelper.HasRights(this.UserId.ToString(), this.Controller, m.Name) == false){
					return Error("没有权限", 405);
				}
			}
			if (isMustLogin && (string.IsNullOrWhiteSpace(this.UserId.ToString())||this.UserId==0 )) {
				Log.WriteLines(
					"执行该操作必须登录",
					Request.QueryString.GetQuery()
					);
				return Error("执行该操作必须登录", 4009);
			}
            if (isMustRole && !RoleBcAttribute.CheckRole(this.UserId))
            {
                return Error("无执行此操作权限", 401);
            }
            //var attr = (MustRights)attribs.FirstOrDefault(item => item is MustRights);
            //if (attr != null && attr.Check(UserInfo.StaffNo) == false) {
            //	return Error("没有权限", 405);
            //}
            //var actionRole = (RoleBcActionAttribute)attribs.FirstOrDefault(item => item is RoleBcAttribute);
            //if (actionRole != null) {
            //	if (!actionRole.CheckAction(UserInfo.StaffNo, this.Controller, action)) {
            //		return Error("没有权限", 405);
            //	}
            //}
            var api需要的参数 = m.GetParameters();
			if (isAutoCovrtFromJSon) {
				if (string.IsNullOrWhiteSpace(parameters) || string.CompareOrdinal(parameters.Trim(), "null") == 0) {
					return Error("该API需要输入数据，但是没有检测到数据", 400);
				}
				if (api需要的参数.Length != 1) {
					throw new ArgumentException(m.Name + " 方法没有输入参数（指定了JsonTypeAttribute的方法只接收一个支持反序列化JSON的对象参数）");
				}
				//var jta = (JsonTypeAttribute)attribs.FirstOrDefault(item => item is JsonTypeAttribute);
				//var param = type == 2 ? GetData<InitParam>(jsonData) : QueryStringHelper.ParseQuery<InitParam>(jsonData);
				var o = JsonTypeAttribute.Parse(parameters, api需要的参数[0].ParameterType, paramType);
				result = m.Invoke(this, new object[] { o });
			} else if (isPassJson) {
				//API需要JSON格式的参数
				if (string.IsNullOrWhiteSpace(parameters) || string.CompareOrdinal(parameters.Trim(), "null") == 0) {
					return Error("该API需要输入数据，但是没有检测到数据", 400);
				}
				if (api需要的参数.Length == 0) {
					throw new ArgumentException(m.Name + " 方法没有输入参数（指定了JSONDataAttribute的方法只接收一个String类型参数）");
				}
				//if (ps.Length > 1) {
				//	throw new ArgumentException(m.Name + " 方法定义了多个参数（指定了JSONDataAttribute的方法只接收一个String类型参数）");
				//}
				if (api需要的参数[0].ParameterType != typeof(string)) {
					throw new ArgumentException(m.Name + " 方法定义的参数不合法（指定了JSONDataAttribute的方法只接收一个String类型参数）");
				}
				//直接把string类型的参数值传入API，API自己解析
				result = m.Invoke(this, new object[] { parameters, paramType });
			} else {
				var 准备传递给api的参数 = new ArrayList();
				if (api需要的参数.Length == 0) {
					result = m.Invoke(this, null);
				} else {
					var 客户传送过来的参数 = paramType == 2
					? parseParam(parameters)
					: QueryStringHelper.ParseQuery(parameters);

					foreach (var p in api需要的参数) {
						if (p.ParameterType.IsAssignableFrom(typeof(IList<int>))
							&& (客户传送过来的参数.AllKeys.Contains(p.Name) || 客户传送过来的参数.AllKeys.Contains(p.Name + "[]"))) {
							var values = 客户传送过来的参数[p.Name + "[]"] ?? 客户传送过来的参数[p.Name];
							var ids = new List<int>();
							foreach (var v in values.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) {
								var i = 0;
								if (int.TryParse(v, out i)) {
									ids.Add(i);
								}
							}
							准备传递给api的参数.Add(ids);
						} else if (p.ParameterType.IsAssignableFrom(typeof(IList<string>))
							&& (客户传送过来的参数.AllKeys.Contains(p.Name) || 客户传送过来的参数.AllKeys.Contains(p.Name + "[]"))) {
							var values = 客户传送过来的参数[p.Name + "[]"] ?? 客户传送过来的参数[p.Name];
							var lines = values.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
							准备传递给api的参数.Add(lines);

						} else if (客户传送过来的参数.AllKeys.Contains(p.Name)) {
							//转换参数值
							var converter = TypeDescriptor.GetConverter(p.ParameterType);
							if (!converter.CanConvertFrom(typeof(string))) continue;
							var o = converter.ConvertFrom(客户传送过来的参数[p.Name]);
							if (o != null) {
								准备传递给api的参数.Add(o);
							}
						} else if (p.IsOptional) {
							//可选参数使用默认值
							//处理 DateTime
							if (p.ParameterType == typeof(DateTime)) {
								准备传递给api的参数.Add(default(DateTime));
							} else {
								准备传递给api的参数.Add(p.DefaultValue ?? p.RawDefaultValue);
							}
						} else {
							//即不是可选参数又没有传送过来，报错
							throw new ArgumentException(p.Name);
						}
					}
					result = m.Invoke(this, 准备传递给api的参数.ToArray());
				}
			}
			return result;
		}
		/// <summary>
		/// 当前的API动作
		/// </summary>
		public string Action { get; set; }

		/// <summary>
		/// 返回数据
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="data"></param>
		/// <returns></returns>
		protected static T GetData<T>(string data) {
			return data.FromJson<T>();
		}
		/// <summary>
		/// 处理参数
		/// </summary>
		/// <param name="str"></param>
		/// <returns></returns>
		protected NameValueCollection parseParam(string str) {
			var nv = new NameValueCollection();
			if (string.IsNullOrWhiteSpace(str)) {
				Log.Error("解析参数失败！没有数据");
				return nv;
			}
			try {
				//var r = JsonConvert.DeserializeObject<Dictionary<string, object>>(str);
				var r = str.FromJson<Dictionary<string, object>>();
				foreach (var key in r.Keys) {
					var o = r[key];
					if (o is Newtonsoft.Json.Linq.JArray) {
						var arr = o as JArray;
						var arrL = new ArrayList();
						foreach (var item in arr) {
							arrL.Add(item);
						}
						nv.Add(key, arrL.Join(","));
					} else {
						nv.Add(key, r[key].ToString());
					}
				}
			} catch (Exception ex) {
				Log.Error(ex);
			}
			return nv;
		}

		/// <summary>
		/// Action执行车成功请调用此方法返回数据
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		protected ApiResult Success(object obj) {
			return new ApiResult() {
				Success = true,
				Data = obj
			};
		}
		/// <summary>
		/// 执行Action时发生错误请调用此方法
		/// </summary>
		/// <param name="Message"></param>
		/// <param name="code"></param>
		/// <param name="data"></param>
		/// <returns></returns>
		protected ApiResult Error(string Message, int code = -1, object data = null) {
			//Log.Error("执行API发生错误:{0}\n{1}", "API", Message, code);
			var ip = Request.GetClientIpAddress();
			Log.Error("{0}--{1}\n执行API（{2}.{3}）错误：\n{4}-{5}", "API",
					ip, this.ApiApp != null ? this.ApiApp.AppName : "NNNN",
					this.Controller, this.Action,
					Message, code
					);
			return new ApiResult() {
				Success = false,
				Code = code,
				Message = Message,
				Data = data
			};
		}
		/// <summary>
		/// 未开发完成的API返回的错误信息
		/// </summary>
		/// <returns></returns>
		protected ApiResult NotDoneError() {
			return Error("革命尚未成功");
		}
		/// <summary>
		/// 执行Action时发生错误请调用此方法
		/// </summary>
		/// <param name="exp"></param>
		/// <param name="code"></param>
		/// <returns></returns>
		protected ApiResult Error(Exception exp, int code = 0) {
			var exception = exp as DbEntityValidationException;
			var ip = Request.GetClientIpAddress();
			if (exception != null) {
				var sb = new StringBuilder();
				var dbvex = exception;
				foreach (var error in dbvex.EntityValidationErrors.Where(err => err.IsValid == false).SelectMany(err => err.ValidationErrors)) {
					sb.AppendFormat("{0}:{1}\r\n", error.PropertyName, error.ErrorMessage);
				}
				//Log.Error("执行API发生错误:{0}\n{1}\n{2}", "API", exp.Message, exp, sb);
				Log.Error("{0}--{1}\r\n执行API（{2}.{3}）错误：\r\n{4}-{5}\r\n{6}", "API",
						ip, this.ApiApp != null ? this.ApiApp.AppName : "NNNN",
						this.Controller, this.Action,
						exp.Message, code, sb
						);
			} else {
				//Log.Error("执行API发生错误:{0}\n{1}", "API", exp.Message, exp);
				Log.Error("{0}--{1}\r\n执行API（{2}.{3}）错误：\r\n{4}-{5}\r\n{6}\r\n{7}", "API",
						ip, this.ApiApp != null ? this.ApiApp.AppName : "NNNN",
						this.Controller, this.Action,
						exp.Message, code,
						exp.ToString(),
						exp.StackTrace
						);
			}

			if (Request.IsLocal)
				return new ApiResult() {
					Success = false,
					Code = code,
					Message = exp.Message,
					ExtMsg = exp.ToString()
				};
			return new ApiResult() {
				Success = false,
				Code = code,
				Message = exp.Message
			};
		}
		/// <summary>
		/// 获取当前控制器的所有API信息（不包括GetDTD）
		/// </summary>
		/// <param name="Action"></param>
		/// <param name="Key"></param>
		/// <returns></returns>
		// ReSharper disable once InconsistentNaming
		public ApiResult GetDTD(string Action = "", string Key = "") {
			if (Action == "Search") {
				return SearchApi(Key);
			}
			var type = GetType();
			var ms = type.GetMethods();
			Action = this.Request.Get("action", Action);
			if (string.IsNullOrWhiteSpace(Action)) {
				var apiList = ms.Where(item =>
					item.ReturnType == typeof(ApiResult) &&
					string.CompareOrdinal(item.Name, "GetDTD") != 0);
				return Success(apiList
					.OrderBy(m => m.Name)
					.Select(m => GetApiInfo(this.GetType(), m, false)).ToArray());
			}
			var a = ms.FirstOrDefault(item =>
				item.Name == Action &&
				item.ReturnType == typeof(ApiResult) &&
				string.CompareOrdinal(item.Name, "GetDTD") != 0);
			return a == null
				? Error("找不到指定的 Action（" + Action + "）", 404)
				: Success(GetApiInfo(this.GetType(), a, true));
		}

		private ApiResult SearchApi(string Key) {
			var cacheKey = "all-api-list";
			var allApiList = myCache.Get<IList<string>>(cacheKey);
			if (!allApiList.Any() || !myCache.Exists(cacheKey)) {

			}
			return Success(allApiList.Contains(Key));
		}

		private int type = 0;
		/// <summary>
		/// 是否後臺方法
		/// </summary>
		public bool IsBackend {
			get {
				if (type > 0) {
					return type == 1;
				}
				type = 2;
				if (checkBackend(this.GetType())) {
					type = 1;
					return true;
				}
				var ms = GetType().GetMethods();

				var apiList = ms.Where(item =>
					item.ReturnType == typeof(ApiResult) &&
					string.CompareOrdinal(item.Name, "GetDTD") != 0);
				if (apiList.Where(checkBackend).Any()) {
					type = 1;
					return true;
				}
				return false;
			}
		}

		static bool checkBackend(Type type) {
			var attribs = type.GetCustomAttributes(false);
			var isMustAdmin = attribs.Any(item => item is MustAdminAttribute);
			var isMustBackend = attribs.Any(item => item is MustBackendAttribute);
			return isMustAdmin || isMustBackend;
		}
		static bool checkBackend(MethodInfo api) {
			var attribs = api.GetCustomAttributes(false);
			var isMustAdmin = attribs.Any(item => item is MustAdminAttribute);
			var isMustBackend = attribs.Any(item => item is MustBackendAttribute);
			return isMustAdmin || isMustBackend;
		}

        public string ConnLinux(string server, string username, int port, string password, string command)
        {
            try
            {
                using (var client = new SshClient(server, port, username, password))
                {
                    try
                    {
                        client.Connect();
                        var cmd = client.CreateCommand(command);
                        cmd.Execute();
                        client.Disconnect();
                        return cmd.Result;
                    }
                    catch (Exception e1)
                    {
                        return e1.Message;
                    }
                }
            }
            catch (Exception e1)
            {
                return e1.Message;
            }
        }

        #region 解析类型
        /// <summary>
        /// 获取Type的定义
        /// </summary>
        /// <param name="type"></param>
        /// <param name="dp"></param>
        /// <returns></returns>
        static object GetTypeDtd(Type type, int dp = 0) {
			if (dp > 9) return null;
			var properties = type.GetProperties();
			var hashTable = new Hashtable();
			foreach (var p in properties) {
				var ignore = p.IsDefined(typeof(JsonIgnoreAttribute));
				if (ignore) continue;
				var t = p.PropertyType;

				var pd = p.GetCustomAttribute<ParamDescriptionAttribute>();
				var description = "";
				object defaultValue = null;
				if (pd != null) {
					description = pd.Description;
					defaultValue = pd.DefaultValue;
				} else {
					var desc = (DescriptionAttribute)p.GetCustomAttribute(typeof(DescriptionAttribute));
					description = desc?.Description;
				}
				var tpmHashTable = new Hashtable();
				ParseType(p.Name, t, tpmHashTable, dp);
				var fullName = string.Format("{0}({1})", p.Name, t.Name);
				if (string.IsNullOrWhiteSpace(description)) {
					if (tpmHashTable.ContainsKey(p.Name)) {
						hashTable.Add(p.Name, tpmHashTable[p.Name]);
					} else {
						hashTable.Add(fullName, tpmHashTable[fullName]);
					}
				} else {
					if (tpmHashTable.ContainsKey(p.Name)) {
						hashTable.Add(p.Name, new {
							类型 = tpmHashTable[p.Name],
							说明 = description,
							默认值 = defaultValue,
						});
					} else {
						hashTable.Add(fullName, new {
							类型 = tpmHashTable[fullName],
							说明 = description,
							默认值 = defaultValue,
						});
					}
				}
			}
			if (hashTable.Count == 0) return type;
			return hashTable;
		}

		static void ParseType(string vName, Type t, IDictionary hashTable, int dp) {
			while (true) {
				if (t == typeof(string)) {
					//hashTable.Add(vName, new {
					//	type = "String"
					//});
					hashTable.Add(vName, "String");
				} else if (t == typeof(int)) {
					//hashTable.Add(vName, new {
					//	type = "Int"
					//});
					hashTable.Add(vName, "Int");
				} else if (t == typeof(short)) {
					//hashTable.Add(vName, new {
					//	type = "Int"
					//});
					hashTable.Add(vName, "Short = Int(16)");
				} else if (t == typeof(long)) {
					//hashTable.Add(vName, new {
					//	type = "Int"
					//});
					hashTable.Add(vName, "Long = Int(64)");
				} else if (t == typeof(float)) {
					//hashTable.Add(vName, new {
					//	type = "Int"
					//});
					hashTable.Add(vName, "Float");
				} else if (t == typeof(double)) {
					//hashTable.Add(vName, new {
					//	type = "Int"
					//});
					hashTable.Add(vName, "Double");
				} else if (t == typeof(decimal)) {
					//hashTable.Add(vName, new {
					//	type = "Decimal"
					//});
					hashTable.Add(vName, "Decimal");
				} else if (t == typeof(bool)) {
					//hashTable.Add(vName, new {
					//	type = "Boolean"
					//});
					hashTable.Add(vName, "Boolean");
				} else if (t == typeof(DateTime)) {
					//hashTable.Add(vName, new {
					//	type = "DateTime"
					//});
					hashTable.Add(vName, "DateTime");
				} else if (t == typeof(Guid)) {
					hashTable.Add(vName, "GUID");
				} else if (t == typeof(IList<int>) || t == typeof(List<int>)) {
					hashTable.Add(vName, "List<int>");
				} else if (t == typeof(IList<string>) || t == typeof(List<string>)) {
					hashTable.Add(vName, "List<string>");
				} else if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) {
					t = Nullable.GetUnderlyingType(t);
					continue;
					//} else if (t.IsGenericType) {
					//    var args = t.GetGenericArguments();
					//    if (args.Length == 1) {
					//        hashTable.Add(vName, $"List<{args[0].Name}>");
					//    } else if (args.Length == 2) {
					//        hashTable.Add(vName, $"Dict<{args[0].Name}>={args[1].Name}");
					//    } else {
					//        hashTable.Add(string.Format("{0}({1})", vName, t.Name), GetTypeDtd(t, dp + 1));
					//    }
				} else if (t.IsEnum) {
					hashTable.Add(vName, "Int");
				} else {
					hashTable.Add($"{vName}({t.Name})", GetTypeDtd(t, dp + 1));
				}
				break;
			}
		}

		/// <summary>
		/// 获取Type的定义
		/// </summary>
		/// <param name="type"></param>
		/// <param name="dp"></param>
		/// <returns></returns>
		static object GetReturnTypeDtd(ReturnTypeAttribute type, int dp = 0) {
			var r = GetTypeDtd(typeof(ApiResult));
			if (type == null) return r;
			var ht = (Hashtable)r;
			ht.Remove("Data(Object)");

			var hashTable = new Hashtable();
			var t = type.ReturnType;
			var pName = t.FullName;
			ParseType(pName, t, hashTable, 0);

			if (hashTable.ContainsKey(pName)) {
				ht.Add("Data", new {
					类型 = hashTable[pName],
					说明 = type.Description

				});
			} else {
				ht.Add($"Data({type.ReturnType.Name})",
					new {
						类型 = hashTable[$"{pName}({t.Name})"],
						说明 = type.Description
					}
				);
			}
			return ht;
		}

		private static object GetParameterTypeDtd(ParameterInfo p) {
			var pd = p.GetCustomAttribute<ParamDescriptionAttribute>();
			var description = "";
			//object defaultValue = null;
			if (pd != null) {
				description = pd.Description;
				//defaultValue = pd.DefaultValue;
			} else {
				var desc = (DescriptionAttribute)p.GetCustomAttribute(typeof(DescriptionAttribute));
				description = desc?.Description;
			}
			var hashTable = new Hashtable();
			var type = p.ParameterType;
			var pName = type.FullName;
			ParseType(pName, type, hashTable, 0);
			if (p.IsOptional) {
				return new {
					名称 = p.Name,
					是否可选 = p.IsOptional,
					默认值 = (p.ParameterType == typeof(DateTime))
						? default(DateTime)
						: p.DefaultValue,
					类型 = hashTable.ContainsKey(pName)
						? hashTable[pName]
						: hashTable[$"{pName}({type.Name})"],
					说明 = description
				};
			}
			return new {
				名称 = p.Name,
				是否可选 = false,
				类型 = hashTable.ContainsKey(pName)
						? hashTable[pName]
						: hashTable[$"{pName}({type.Name})"],
				说明 = description
			};
		}
		/// <summary>
		/// 获取Type的定义
		/// </summary>
		/// <param name="type"></param>
		/// <param name="dp"></param>
		/// <returns></returns>
		static object[] GetInputParamTypeDtd(Type type, int dp = 0) {
			if (type == null || dp > 9) return null;
			var properties = type.GetProperties();
			var arrayList = new ArrayList();
			foreach (var p in properties) {
				var t = p.PropertyType;
				//if (BlockParamNames.Contains(p.Name))
				//    continue;
				var pd = p.GetCustomAttribute<ParamDescriptionAttribute>(false);
				var description = p.GetCustomAttribute<DescriptionAttribute>(false);
				var jsonProperty = p.GetCustomAttribute<JsonPropertyAttribute>(false);

				var varType = t.Name;
				if (varType == "List`1" || varType == "IList`1") {
					if (t == typeof(IList<int>) || t == typeof(List<int>)) {
						varType = "List<Int>";
					} else if (t == typeof(IList<string>) || t == typeof(List<string>)) {
						varType = "List<string>";
					}
				}
				var pName = jsonProperty == null
					? p.Name
					: (string.IsNullOrWhiteSpace(jsonProperty.PropertyName) ? p.Name : jsonProperty.PropertyName);
				var oDefalutValue = pd?.DefaultValue;
				if (pd == null) {
					arrayList.Add(new {
						名称 = pName,
						类型 = varType,
						说明 = description?.Description,
						是否可选 = (jsonProperty != null) && (jsonProperty.Required != Required.Always)
					});
				} else {
					arrayList.Add(new {
						名称 = pName,
						类型 = varType,
						说明 = pd.Description,
						默认值 = oDefalutValue,
						是否可选 = (jsonProperty != null) && (jsonProperty.Required != Required.Always)
					});
				}
			}
			if (arrayList.Count == 0) return null;
			return arrayList.ToArray();
		}

		/// <summary>
		/// 获取API的定义信息
		/// </summary>
		/// <param name="ClassType"></param>
		/// <param name="api"></param>
		/// <param name="isFull"></param>
		/// <returns></returns>
		static object GetApiInfo(Type ClassType, MethodInfo api, bool isFull) {
			var attribs = api.GetCustomAttributes(false);
			var isMustLogin = ClassType.GetCustomAttribute<MustLoginAttribute>(true) != null || attribs.Any(item => item is MustLoginAttribute);
			var isMustAdmin = ClassType.GetCustomAttribute<MustAdminAttribute>(true) != null || attribs.Any(item => item is MustAdminAttribute);
			var isMustBackend = ClassType.GetCustomAttribute<MustBackendAttribute>(true) != null || attribs.Any(item => item is MustBackendAttribute);
			var isMustSplitPage = attribs.Any(item => item is MustSplitPageAttribute);

			var obs = api.GetCustomAttribute<ObsoleteAttribute>();
			var version = api.GetCustomAttribute<ApiVersionAttribute>();
			var returnType = (ReturnTypeAttribute)attribs.FirstOrDefault(item => item is ReturnTypeAttribute);
			var description = (DescriptionAttribute)attribs.FirstOrDefault(item => item is DescriptionAttribute);
			if (isFull) {
				object[] Params;
				if (attribs.Any(item => item is JsonTypeAttribute)) {
					Params = GetInputParamTypeDtd(api.GetParameters().FirstOrDefault()?.ParameterType);
				} else {
					Params = api.GetParameters().Select(GetParameterTypeDtd).ToArray();
				}

				return new {
					名称 = api.Name,
					弃用 = obs == null ? null : new {
						obs.Message
					},
					程序集 = GetDllInfo(ClassType),
					说明 = description == null ? "<暂无>" : description.Description,
					版本 = version == null ? "-" : version.Vesion,
					权限 = new {
						必须登录 = isMustLogin || isMustBackend || isMustAdmin,
						必须管理员 = isMustAdmin,
						必须是后台用户 = isMustBackend || isMustAdmin
					},
					参数 = Params,
					支持分页 = isMustSplitPage,
					返回值 = GetReturnTypeDtd(returnType)
				};
			}

			return new {
				名称 = api.Name,
				弃用 = obs == null ? null : new {
					obs.Message
				},
				程序集 = GetDllInfo(ClassType),
				说明 = description == null ? "<暂无>" : description.Description,
				版本 = version == null ? "-" : version.Vesion,
				权限 = new {
					必须登录 = isMustLogin || isMustBackend || isMustAdmin,
					必须管理员 = isMustAdmin,
					必须是后台用户 = isMustBackend || isMustAdmin
				},
				支持分页 = isMustSplitPage,
			};
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="clasType"></param>
		/// <returns></returns>
		static object GetDllInfo(Type clasType) {
			var ver = clasType.Assembly.GetName();
			return new {
				ver.Name,
				Version = ver.Version.ToString(),
				ver.FullName,
			};
		}

		#endregion
	}
	/// <summary>
	/// API统一返回结构
	/// </summary>
	public class ApiResult {
		/// <summary>
		/// API是否执行成功
		/// </summary>
		[ParamDescription("表示该API是否执行成功", DefaultValue = true)]
		public bool Success { get; set; }
		/// <summary>
		/// 错误代码
		/// </summary>
		[ParamDescription("错误代码，0-无错误", DefaultValue = -1)]
		public int Code { get; set; }
		/// <summary>
		/// 错误信息
		/// </summary>
		[ParamDescription("错误描述")]
		public string Message { get; set; }
		/// <summary>
		/// 扩展信息
		/// </summary>
		[ParamDescription("详细的错误信息，Debug模式下有效")]
		public string ExtMsg { get; set; }
		/// <summary>
		/// 返回数据
		/// </summary>
		[ParamDescription("该API返回的数据")]
		public object Data { get; set; }
	}
	/// <summary>
	/// 找不到符合请求的API Handler时返回这个默认Handler
	/// </summary>
	public class DefaultHandler : IHttpHandler, IReadOnlySessionState {
		/// <summary>
		/// 
		/// </summary>
		public bool IsReusable => false;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		public void ProcessRequest(HttpContext context) {
			var response = context.Response;

			BaseHandler.SetHeader(response);
			response.AddHeader("Content-Type", "application/json");
			response.Write((new {
				Success = false,
				Message = "没有任何API",
				Code = 404,
				Url = context.Request.RawUrl
			}).ToJson());
		}
	}
	/// <summary>
	/// 相应OPTIONS的通用API
	/// </summary>
	public class OptionsHandler : IHttpHandler, IReadOnlySessionState {
		/// <summary>
		/// 
		/// </summary>
		public bool IsReusable => false;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		public void ProcessRequest(HttpContext context) {
			var response = context.Response;

			BaseHandler.SetHeader(response);
			response.AddHeader("Content-Type", "application/json");
			response.Write((new {
				Success = true,
				Message = "HELLO"
			}).ToJson());
		}
	}

	/// <summary>
	/// App配置信息
	/// </summary>
	public class ApiConfig {
		/// <summary>
		/// ID
		/// </summary>
		public Guid ID { get; set; }

		/// <summary>
		/// App名称
		/// </summary>
		public string AppName { get; set; }

		/// <summary>
		/// App密钥
		/// </summary>
		public string AppSecret { get; set; }

		/// <summary>
		/// App类型
		/// </summary>
		public int AppType { get; set; }
		/// <summary>
		/// 操作系统类型
		/// 1-IOS
		/// 2-安卓
		/// 3-WP
		/// </summary>
		public int OsType { get; set; }
	}
}
